/*
 * Copyright (C) 2006-2007 Eskil Bylund
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;
using System.Collections;

using Gtk;
using Mono.Unix;

using DCSharp.Backend.Connections;
using DCSharp.Backend.Managers;

namespace DCSharp.Gui
{
	public class ConnectionStatusbar : Statusbar
	{
		private ConnectionManager connectionManager;

		private long totalDown;
		private long totalUp;

		private Label downLabel;
		private Label upLabel;
		private Tooltips tooltips;
		private EventBox eventBox;

		private uint timeout;

		public ConnectionStatusbar(ConnectionManager connectionManager) : base()
		{
			if (connectionManager == null)
			{
				throw new ArgumentNullException("connectionManager");
			}
			this.connectionManager = connectionManager;

			HasResizeGrip = false;

			tooltips = new Tooltips();

			// Hide existing label
			HideAll();

			// Statusbar
			Frame frame = new Frame();
			frame.ShadowType = (ShadowType)StyleGetProperty("shadow-type");
			Add(frame);

			eventBox = new EventBox();
			eventBox.AboveChild = true;
			eventBox.VisibleWindow = false;
			frame.Add(eventBox);

			Box mainBox = new HBox(false, 12);
			eventBox.Add(mainBox);

			Box box;
			downLabel = new Label();
			upLabel = new Label();

			box = new HBox(false, 4);
			box.PackStart(new Image(Stock.GoDown, IconSize.Menu), false, true, 0);
			box.PackStart(downLabel, false, true, 0);
			mainBox.Add(box);

			box = new HBox(false, 4);
			box.PackStart(new Image(Stock.GoUp, IconSize.Menu), false, true, 0);
			box.PackStart(upLabel, false, true, 0);
			mainBox.Add(box);

			frame.ShowAll();

			Update();

			// Events
			connectionManager.UserConnected += OnUserConnected;
			connectionManager.UserDisconnected += OnUserDisconnected;
		}

		#region Methods

		protected override void OnDestroyed()
		{
			connectionManager.UserConnected -= OnUserConnected;
			connectionManager.UserDisconnected -= OnUserDisconnected;

			if (timeout != 0)
			{
				GLib.Source.Remove(timeout);
				timeout = 0;
			}
			base.OnDestroyed();
		}

		private bool Update()
		{
			int downloadCount = 0;
			int uploadCount = 0;
			double down = 0;
			double up = 0;

			long totalDown = this.totalDown;
			long totalUp = this.totalUp;

			lock (connectionManager.SyncRoot)
			{
				foreach (UserConnection connection in connectionManager)
				{
					if (connection.Downloading)
					{
						down += connection.Monitor.DownloadSpeed;
						downloadCount++;
					}
					else if (connection.Uploading)
					{
						up += connection.Monitor.UploadSpeed;
						uploadCount++;
					}
					totalDown += connection.Monitor.BytesDownloaded;
					totalUp += connection.Monitor.BytesUploaded;
				}
			}

			// Labels
			downLabel.Text = String.Format("{0}/s", Util.FormatFileSize((long)down));
			upLabel.Text = String.Format("{0}/s", Util.FormatFileSize((long)up));

			if (totalDown > 0)
			{
				downLabel.Text += " - " + String.Format(Catalog.GetString("Total: {0}"),
					Util.FormatFileSize(totalDown));
			}
			if (totalUp > 0)
			{
				upLabel.Text += " - " + String.Format(Catalog.GetString("Total: {0}"),
					Util.FormatFileSize(totalUp));
			}

			// Tooltip
			string tooltip = String.Format(Catalog.GetPluralString(
				"{0} active download", "{0} active downloads", downloadCount),
				downloadCount);

			tooltip += ", ";

			tooltip += String.Format(Catalog.GetPluralString(
				"{0} active upload", "{0} active uploads", uploadCount),
				uploadCount);

			tooltips.SetTip(eventBox, tooltip, null);

			return true;
		}

		private void OnUserConnected(object obj, EventArgs args)
		{
			if (timeout == 0)
			{
				timeout = GLib.Timeout.Add(1000, Update);
			}
		}

		private void OnUserDisconnected(object obj, ConnectionEventArgs args)
		{
			ConnectionMonitor monitor = ((UserConnection)args.Connection).Monitor;

			totalDown += monitor.BytesDownloaded;
			totalUp += monitor.BytesUploaded;

			if (connectionManager.Count == 0)
			{
				if (timeout != 0)
				{
					GLib.Source.Remove(timeout);
					timeout = 0;
				}

				Application.Invoke(delegate
				{
					Update();
				});
			}
		}

		#endregion
	}
}
